package way.learning.zz;

import way.learning.zz.source.CachedFileElement;
import way.learning.zz.source.FileElement;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;

import static java.lang.Long.MAX_VALUE;
import static java.util.concurrent.TimeUnit.DAYS;

/**
 * Utility functions for internal usage.
 */
public class Util {

    private static final Logger LOG = LoggerFactory.getLogger(Util.class);

    Util() {
        throw new AssertionError("Not meant for instantiation");
    }

    public static Set<FileElement> copyValuesToFileElementSet(Map<String, CachedFileElement> files) {
        Set<FileElement> result = new HashSet<FileElement>();
        for (CachedFileElement file : files.values()) {
            result.add(file.getFileElement());
        }
        return result;
    }

    static Map<String, CachedFileElement> newLinkedHashMap() {
        return new LinkedHashMap<String, CachedFileElement>();
    }

    static void awaitTermination(ExecutorService executor) {
        while (true) {
            try {
                executor.awaitTermination(MAX_VALUE, DAYS);
                return;
            } catch (InterruptedException e) {
                LOG.warn("Thread interrupted, but ignored.");
            }
        }
    }


    /**
     *callable是一个接口，callable的一个具体实现就是一个任务，这个方法的作用就是调度任务进行执行
     *返回任务结果
     */
    static <T> Future<T> invokeTask(String threadName, Callable<T> callable) {

        /**
         * 创建一个FutureTask，它将在运行时执行给定的Callable
         * Future就是对于具体的Runnable或者Callable任务的执行结果进行取消、查询是否完成、获取结果。
         * 必要时可以通过get方法获取执行结果，该方法会阻塞直到任务返回结果
         *
         * FutureTask实现了RunnableFuture接口,而RunnableFuture继承了Runnable接口和Future接口
         * 所以它既可以作为Runnable被线程执行，又可以作为Future得到Callable的返回值
         */
        FutureTask<T> task = new FutureTask<T>(callable);
        Thread t = new Thread(task);
        t.setName(threadName);
        t.start();
        return task;
    }
}
